Conversation
…atch The three bits range-selection givens (the low-0 form, the width+low form, and the H-form for the annotation path) collapse into one over `DFBitsWL[W, L2]` receivers. What kept them apart was never the receiver shapes: a `CheckNUB[HI, HighIdx[W, L2]]` bound routes the fold application through `UBound.Aux`, where the const-guard's reduction is context-dependent. It can collapse to `Int` inside the implicit search while the same application reduces to a literal in the required type, so the found candidate no longer conforms: a real violation surfaced as a raw given-mismatch dump instead of the check's message, and a valid selection on an annotation-path receiver could fail to resolve outright (the reason the H-form existed). `IntP.HighIdxOf` now makes the literal-vs-wide decision by given prioritization instead of a guard: the literal instance computes `W + L - 1` in raw `compiletime.ops` over `Int & Singleton` arguments, the wide instance answers `Int`, and the op given feeds the check a plain, already-decided type parameter. Static checks fire wherever the receiver's bounds reduce, degrade to their elaboration-time half where they do not, and a static failure renders the real message: an out-of-range selection on a `BitsHL[9, 2] <> VAL` struct field now reports "Index 15 is above the high index 9 of the selected value" at the user's expression, identical to the direct-declaration case. Fixes #488 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Porting VeeR's rvdff_fpga needs a cell whose clock input the baseline calls `rawclk` while a second, dead input is called `clk`. That works, and the mechanism is worth writing down: @timing.clock(portName = ...) renames the port, and the parent still binds its own clock to it, because the magnet matches by domain rather than by name. The domain then propagates down, so a grandchild is emitted with the renamed port too. Two traps come with it. A renamed-clock design must stay childless, or the emission is invalid SystemVerilog: duplicated rst_l_0/rst_l_1 ports against a .rst_l connection, plus a hierarchical assign through the module type name. It elaborates clean and only slang catches it, so run the emitted files through slang after a rename. And `val clk = Clk <> IN` silently wins over portName, dropping the renamed port and moving the registers onto whatever the parent wires to `clk` -- so the second clock input has to be a plain Bit, which the magnet leaves alone despite the name. Also corrects the clock-only-annotation bullet, which is expected behaviour (a domain with an init and no reset signal) rather than the bug it reads as, and whose emitted form has drifted to an `initial` block. Restate @..reset alongside a rename when the module does reset. The general half of the rename behaviour is marked as a user-guide doc gap. Submodule: benchmarks moves to the upstream-copyright sweep. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`x := Vector.fill(16)(1)` and `x := Vector(0, 1, 1, ...)` were rejected for a `Bit X 16` receiver. Scala widens the singleton literal types when it infers a collection's element type, so both come out as `Vector[Int]`, and `Int` is no candidate for a `Bit` cell: only `BitNum` is. Exact already restores exact types term by term, so it is where the widening is undone. A new `asBitCollection` step retypes a collection as `C[BitNum]` when the application's LAST argument list holds nothing but 0 or 1 literals. Reading the last list is what covers both forms: for `Vector(0, 1, ...)` it is the vararg `Repeated`, and for `Vector.fill(16)(1)` it is the element argument, so the length never enters the decision. `Vector.tabulate(16)(f)`, and any literal that is neither 0 nor 1, do not match and pass through untouched. `BitNum` stays a subtype of `Int`, so a collection headed for a decimal vector is unaffected: `IntInfo` reads the union exactly as it reads `Int`, and `Vector(0, 1, 0, 1)` into a `UInt(8) X 4` still yields 8-bit constants. The retyping is restricted to an `Iterable`, where the element type erases to a reference and the cast is a runtime no-op; an `Array`, whose element type survives erasure, is deliberately left alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t is anonymous
`MetaContextGenPhase` lets an owner-less apply keep the context propagated into it,
rather than minting an anonymous one, whenever the applied function's name carries a
`$`: proxies, anonymous functions and default getters all build a value that belongs
to the context around them.
An inline accessor (`inline$foo`) carries one too, and it should not. The compiler
mints it only so an inline expansion can reach a member it cannot name directly, so
it stands for the user-written call. The `b`/`h` interpolators expand to
`DFBits.StrInterp.inline$interpolate`, which meant an anonymous interpolated constant
kept the enclosing design's own context, and a design's context is named after the
instance val in its parent:
class Foo extends RTDesign:
val movecircle = new Bar
...
class Bar extends RTDesign:
val x = corners == b"4'1001" // printed as `val movecircle: Bits[4] <> CONST`
So the name leaked across the hierarchy, into a design that never mentions it. Strip
the `inline$` prefix before the `$` test. The constant now gets `setMetaAnon`, and
with it a position on the user's own line instead of one inside `DFBits.scala`.
Three existing expectations had the leak baked in, all of them an enclosing
`RTDomain a` naming an anonymous constant `a` / `a_0` / `a_1`; the constants now
print inline, unnamed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Designs that one Scala declaration elaborated several of (`class Bar`
instantiated with two different parameters) were emitted as `Bar_0.sv` and
`Bar_1.sv`, one file per specialization. They now share a single `Bar.sv`.
`DB.designFileNameMap` is the one place that decides it: designs group by
their `dclMeta` namespace and position, and a group of more than one recovers
the declaration's name from its members' longest common prefix, cut back to
its last `_`. Reading the suffix off the GROUP is what tells an enumerated
`Bar_0` apart from a declared `Adder_8` (a lone design keeps its whole name),
and it covers every suffix form: elaboration's `_<n>`, `UniqueDesigns`', and
the instance-named clones `ReduplicateDesign` makes (`Foo_a`/`Foo_b` -> `Foo`).
Two constraints the AES suite pinned down:
- File names stay unique CASE-INSENSITIVELY, so the output is the same on
every OS. AES has a `cipher` sub-design under a `Cipher` top; the recovered
name collides, and the sub-design keeps `cipher_0` as it had before.
- A design with an UNKNOWN position is declared in no Scala source, so it
groups only with itself rather than with every other such design.
`Printer.designFileGroups` topologically sorts the groups: post-order per
design no longer suffices once positions merge (`Top{P{Bar(22)}, Q{Bar(42)}}`
would put `P` ahead of the `Bar` file it instantiates), and VHDL analysis
order depends on it. A cycle breaks at its first back edge.
Verilator: `-Wno-DECLFILENAME` on every lint/simulate run, since a file named
after a declaration is by construction not named after the one module it
declares. Its `.vlt` waivers filtered on `-file "<dclName>.*"` and so stopped
matching once the file moved; they go through `designFileNameMap` now. A
waiver can no longer single out one design from its file-mates, which is
inherent to their sharing a file, and the `-match` pattern still narrows it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`initFile` bakes file contents into a Const, but only the body knows which files it reads, so no cache key can carry them and a changed file was a false hit at both cache tiers. The read now records the file on its design as a SourceFile(External, InitFile, path, contents) that rides the sub-DB into cache entries and the elaborated hierarchical DB, and every hit re-reads and compares (DB.initFilesUnchanged): the design load gate before adopting an entry (a stale child fails the parent's adoption before it commits), and the DFApp elaborate step through factum 0.3.0's new hit-validation hook (Task.cached's `validate`, surfaced as DiskCache.Step.cacheHitValidator). A rejected entry re-elaborates live and overwrites the same key, so contents stay out of the key and stale entries never accumulate. A missing file is a miss, not an error: the live run raises the user-facing error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.